package com.broada.apm.logic.impl;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.UUID;

import org.apache.commons.lang.ArrayUtils;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.broada.apm.base.BaseLogic;
import com.broada.apm.cache.AreaManager;
import com.broada.apm.cache.IndicatorItemManager;
import com.broada.apm.entity.AO;
import com.broada.apm.entity.ApplicationSystem;
import com.broada.apm.entity.NoticeCommandException;
import com.broada.apm.entity.Relation;
import com.broada.apm.entity.Service;
import com.broada.apm.entity.Threshold;
import com.broada.apm.entity.TopoNode;
import com.broada.apm.entity.convert.BeanConvert;
import com.broada.apm.indicator.api.common.ApmDataIndicatorException;
import com.broada.apm.logic.AlertLogic;
import com.broada.apm.logic.ApplicationLogic;
import com.broada.apm.logic.RelationLogic;
import com.broada.apm.logic.ServerLogic;
import com.broada.apm.model.Alert;
import com.broada.apm.model.ConfigItem;
import com.broada.apm.model.ProtocolRelation;
import com.broada.apm.model.Resource;
import com.broada.apm.protocol.L7ModuleManager;
import com.broada.apm.service.internal.IndicatorService;
import com.broada.apm.service.internal.impl.IndicatorServiceImpl;
import com.broada.apm.util.LicUtils;
import com.broada.apm.utils.ApmLogUtils;
import com.broada.apm.utils.ExceptionUtils;
import com.broada.apm.utils.IPUtils;
import com.broada.apm.utils.IdUtils;
import com.google.common.base.Strings;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

public class ApplicationLogicImpl extends BaseLogic implements ApplicationLogic {
	
	private static Logger log = LoggerFactory.getLogger(ApplicationLogicImpl.class);
	
	private static final int Cluster_Type = 2;
	
	private static final int Common_Type= 1;
	
	private static final int Label_Type = 4;
	
	private static final String default_valid_time = "{\"1\":\"00:00:00-23:59:59\",\"2\":\"00:00:00-23:59:59\",\"3\":\"00:00:00-23:59:59\",\"4\":\"00:00:00-23:59:59\",\"5\":\"00:00:00-23:59:59\",\"6\":\"00:00:00-23:59:59\",\"7\":\"00:00:00-23:59:59\"}";
	
	private IndicatorService indicatorService = new IndicatorServiceImpl();
	
	private ServerLogic serLogic = new ServiceLogicImpl();
	
	private AlertLogic alertLogic = new AlertLogicImpl();

	private RelationLogic relaLogic = new RelationLogicImpl();
	
	@Override
	public List<ApplicationSystem> queryApplications() {
		List<ApplicationSystem> apps = new ArrayList<ApplicationSystem>();
		try {
			List<com.broada.apm.model.ApplicationSystem> queryResult = applicationService.getAllApplications();
			apps = BeanConvert.convertApplication(queryResult);
		} catch (Exception e) {
			ExceptionUtils.error(log, "查询系统列表失败", e);
		}
		return apps;
	}

	@Override
	public ApplicationSystem queryApplicationById(String id, String panelId) {
		List<Relation> relationList = new ArrayList<Relation>();
		List<Service> nodeList = new ArrayList<Service>();
		ApplicationSystem application = null;
		try {
			com.broada.apm.model.ApplicationSystem app = applicationService.getApplicationById(id);
			// 将数据库中查询得到的数据转换为页面数据
			application = (ApplicationSystem) BeanConvert.convertOjbect(app);
			if (application != null) {
				// 获取节点关系
				relationList = relaLogic.queryRelationByAppId(id);
				
				List<Service> list = new ArrayList<Service>();
				list = serLogic.queryServiceByAppId(id);
				// 查询节点协议类型
				for (Service serv : list) {
					// 设置指标配置项
					serv.setIndicatorConfig(IndicatorItemManager.getInstance().getTopoItems(serv.getProtocol() == 0 ? serv
							.getAutoDiscoveryProtocol() : serv.getProtocol(), panelId));
					nodeList.add(serv);
					
					//关键节点是80协议
					if(serv.getId().equals(application.getKeyNodeId()) 
							&& (serv.getProtocol() == 80 || serv.getAutoDiscoveryProtocol() == 80)) {
						application.setIsShowHttp(true);
					}
				}
				
				if (application.getApdex_t() <= 0) {
					ConfigItem item = configItemService.getConfigItem("basic.apdex_t");
					if (item != null)
						application.setApdex_t(Float.valueOf(item.getValue()));
				}
				application.setRelations(relationList);
				application.setTopoNodes(nodeList);
			}
		} catch (Exception e) {
			ExceptionUtils.error(log, "查询系统详细信息失败", e);
		}
		return application;
	}

	@Override
	public ApplicationSystem getApplicationInfoById(String appId) {
		com.broada.apm.model.ApplicationSystem app = applicationService.getApplicationById(appId);
		ApplicationSystem application = (ApplicationSystem) BeanConvert.convertOjbect(app);
		return application;
	}

	@Override
	public void addApplicationNameAndApdex(HashMap<String, String> map) {
		try {
			String systemId = map.get("id");
			String name = map.get("name");
			com.broada.apm.model.ApplicationSystem appSystem = new com.broada.apm.model.ApplicationSystem();
			if (StringUtils.isBlank(systemId)) {
				systemId = IdUtils.strSeq();
				appSystem.setId(systemId);
				appSystem.setCreateAt(new Date());
				appSystem.setName(name);
				appSystem.setDisplayOrder(System.currentTimeMillis());
				// 填充默认编码
				appSystem.setAreaCode(AreaManager.DEFAULTCODE);
				appSystem.setOverview(false);
				appSystem.setValidTime(default_valid_time);
				
				ConfigItem item = configItemService.getConfigItem("basic.apdex_t");
				if (item != null)
					appSystem.setApdex_t(Float.valueOf(item.getValue()));
				
				applicationService.addApplication(appSystem);
			} else {
				appSystem = applicationService.getApplicationById(systemId);
				appSystem.setName(name);
				applicationService.updateApplication(appSystem);
				indicatorService.NoticeCommand("reload", "app", systemId);
			}
		} catch (Exception e) {
			ExceptionUtils.error(log, "添加系统失败", e);
		}
	}

	@Override
	public void updateApplicationNameAndApdex(HashMap<String, String> map) throws Exception {
		try {
			String appId = map.get("id");
			if (StringUtils.isNotBlank(appId)) {
				String apdex_t = map.get("apdex_t");
				String name = map.get("name");
				String areaCode = map.get("areaCode");
				String validTime = map.get("validTime");

				com.broada.apm.model.ApplicationSystem app = applicationService.getApplicationById(appId);
				if (app != null) {
					app.setId(appId);
					app.setName(name);
					app.setAreaCode(areaCode);
					app.setApdex_t(Float.parseFloat(apdex_t));
					app.setValidTime(StringUtils.isBlank(validTime.trim()) ? default_valid_time : validTime);
					applicationService.updateApplication(app);
					indicatorService.NoticeCommand("reload", "app", appId);
				}
			}
		} catch (NoticeCommandException e) {
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
			throw e;
		} catch (Exception e) {
			ExceptionUtils.error(log, "修改系统信息失败", e);
			throw e;
		}
	}

	@Override
	public void deleteApplicationById(String id) {
		try {
			ApmLogUtils.backupTopology("front", 1, "deleteApplicationById", id);

			List<com.broada.apm.model.Service> services = serviceService.getServicesByAppId(id);
			for (com.broada.apm.model.Service service : services) {
				// 删除告警阀值配置
				alertLogic.deleteThresholdsByTargetId(id, service.getId(), "threshold", null);
				alertLogic.deleteThresholdsByTargetId(id, service.getId(), "algorithm", "system");
				alertLogic.deleteThresholdsByTargetId(id, service.getId(), "algorithm", "business");
			}
			
			relaLogic.deleteRelationByAppId(id);
			serviceService.deleteServiceByAppId(id);
			
			com.broada.apm.model.ApplicationSystem application = new com.broada.apm.model.ApplicationSystem();
			application.setId(id);
			applicationService.deleteApplication(application);
			// 删除告警
			Alert alert = new Alert();
			alert.setApplicationId(id);
			alertLogic.deleteAlert(alert);
			//通知指标计算 重新加载应用系统
			indicatorService.NoticeCommand("reload", "apps");
		} catch (NoticeCommandException e) {
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
		} catch (Exception e) {
			ExceptionUtils.error(log, "删除系统失败", e);
		}
	}

	@Override
	public TopoNode saveApplicationTopology(String appId, ApplicationSystem app) throws Exception {
		TopoNode result = new TopoNode();
		try {
			List<Service> nodeList = app.getTopoNodes();  // 如果是集群，这里只返回了集群节点
			List<Relation> relaList = app.getRelations();
			List<Relation> newRelationList = new ArrayList<Relation>();
			if (nodeList == null || nodeList.size() < 0) {
				throw new Exception("节点个数不能为零");
			}
			ApmLogUtils.backupTopology("front", 1, "saveApplicationTopology", appId);
			
			List<String> newServiceIds = new ArrayList<String>();
			Map<String, String> servIdMap = new HashMap<String, String>();
			for (Service serv : nodeList) {
				// 修改节点, 集群和普通节点
				if (serv.getNodeType() == Cluster_Type) {
					List<Service> childServices = serLogic.queryChildServiceByApplicationId(serv.getId());
					for (Service child : childServices) {
						serLogic.updateService(child);
						newServiceIds.add(child.getId());
					}
					serLogic.updateService(serv);
					newServiceIds.add(serv.getId());
				} else if (serv.getNodeType() == Label_Type && serv.getId().equals(serv.getName())) {
					String serviceId = UUID.randomUUID().toString().replace("-","");
					String appServiceId = appId + "-" + serviceId;
					serv.setSize("large");
					serv.setCreateBy("manual");
					serv.setNodeType(Label_Type);
					serv.setId(appServiceId);
					serv.setCreatedAt(new Date());
					serLogic.saveService(serv);
					newServiceIds.add(serv.getId());
					servIdMap.put(serv.getName(), serv.getId());
				} else {
					serLogic.updateService(serv);
					newServiceIds.add(serv.getId());
				}
			}
			
			// 保存关系
			List<String> newRelationIds = new ArrayList<String>();
			if (relaList != null) {
				for (Relation rela : relaList) {
					if (StringUtils.isNotBlank(servIdMap.get(rela.getFrom()))) {
						rela.setFrom(servIdMap.get(rela.getFrom()));
					}
					if (StringUtils.isNotBlank(servIdMap.get(rela.getTo()))) {
						rela.setTo(servIdMap.get(rela.getTo()));
					}
					String id = UUID.randomUUID().toString();
					newRelationIds.add(id);
					rela.setId(id);
					newRelationList.add(rela);
					relaLogic.saveRelation(rela);
				}
			}
			
			com.broada.apm.model.ApplicationSystem oldApp = applicationService.getApplicationById(appId);
			if (oldApp != null) {
				relaLogic.deleteRelationByAppId(appId);
				oldApp.setRelationIds(newRelationIds.toArray(new String[newRelationIds.size()]));
				oldApp.setServiceIds(newServiceIds.toArray(new String[newServiceIds.size()]));
				applicationService.updateApplicationWithRelation(oldApp);
			}
			result.setNodes(app.getTopoNodes());
			result.setRelations(newRelationList);
			indicatorService.NoticeCommand("reload", "app", appId);
		} catch (NoticeCommandException e) {
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
			throw e;
		} catch (ApmDataIndicatorException e) {
			ExceptionUtils.error(log, "保存拓扑失败", e);
			throw e;
		}
		return result;
	}
	
	private List<Service> saveApplicationTopologyCluster(String appId, List<Service> nodeList) throws Exception {
		List<Service> vo_services = new ArrayList<Service>();
		try {
			if (nodeList == null || nodeList.isEmpty()) {
				throw new Exception("参数不正确");
			}
			ApmLogUtils.backupTopology("front", 1, "saveApplicationTopologyCluster", appId);
			com.broada.apm.model.ApplicationSystem _app = applicationService.getApplicationWithServiceAndRelById(appId);
			String[] relaIds = _app.getRelationIds();
			String[] nodeIds = _app.getServiceIds();

			// 约定集合第一个元素为集群节点
			Service cluster = nodeList.get(0);
			// nodeIds去重
			if (cluster.getNodeIds() != null) {
				Set<String> set = new HashSet<String>(Arrays.asList(cluster.getNodeIds()));
				String[] ids = set.toArray(new String[set.size()]);
				cluster.setNodeIds(ids);
			}
			// 删除集群中节点的关系
			List<Relation> relas = Lists.newArrayList();
			if(cluster.getNodeIds() != null && cluster.getNodeIds().length > 0) {
				relas = relaLogic.queryRelationByFromOrTo(cluster.getNodeIds());
				relaLogic.deleteRelationByFromOrTo(cluster.getNodeIds());
				// 删除系统中relationId
				for (Relation rela : relas) {
					relaIds = (String[]) ArrayUtils.removeElement(relaIds, rela.getId());
				}
			}
			// 删除集群中节点阈值
			for (Service node : nodeList) {
				// 删除子节点告警阀值配置
				alertLogic.deleteThresholdsByTargetId(appId, node.getId(), "threshold", null);
				alertLogic.deleteThresholdsByTargetId(appId, node.getId(), "algorithm", "system");
				alertLogic.deleteThresholdsByTargetId(appId, node.getId(), "algorithm", "business");
			}
			// 判断是新建集群还是修改集群
			if (StringUtils.isBlank(cluster.getId())) { // 新建集群
				// 普通节点校验协议
				Service serviceOne = nodeList.get(1);
				serviceOne = serLogic.queryServiceById(serviceOne.getId());
				Service serviceTwo = nodeList.get(2);
				serviceTwo = serLogic.queryServiceById(serviceTwo.getId());
				int onePro = serviceOne.getProtocol() != 0 ? serviceOne.getProtocol() : serviceOne
						.getAutoDiscoveryProtocol();
//				int twoPro = serviceTwo.getProtocol() != 0 ? serviceTwo.getProtocol() : serviceTwo
//						.getAutoDiscoveryProtocol();
				serviceOne.setNodeType(3);
				serviceTwo.setNodeType(3);
				serLogic.updateService(serviceOne);
				serLogic.updateService(serviceTwo);
				vo_services.add(serviceOne);
				vo_services.add(serviceTwo);

				String clusId = appId + "-" + IdUtils.strSeq();
				nodeIds = (String[]) ArrayUtils.add(nodeIds, clusId);
				cluster.setId(clusId);
				cluster.setCreatedAt(new Date());
				cluster.setCreateBy("manual");
				cluster.setNodeType(2);
				// 获取加入集群节点的协议
				cluster.setProtocol(onePro);
				// 保存集群
				serLogic.saveService(cluster);
			} else {
				// 修改节点操作目前只会变更nodeIds nodeType貌似前对丢失了 这里重新赋值
				List<Service> destNodeIds = serLogic.queryChildServiceByClusterId(cluster.getId());
				Service destService = nodeList.get(1);
				destService = serLogic.queryServiceById(destService.getId());
				// 加入集群
				if (destNodeIds.size() < cluster.getNodeIds().length) {
					destService.setNodeType(3);
				} else {
					destService.setNodeType(1);
				}
				serLogic.updateService(destService);
				cluster.setNodeType(2);
				serLogic.updateService(cluster);
			}

			// 约定返回集合第一个元素为集群节点
			vo_services.add(0, cluster);

			_app.setServiceIds(nodeIds);
			_app.setRelationIds(relaIds);
			// 修改系统
			applicationService.updateApplicationWithRelation(_app);
			indicatorService.NoticeCommand("reload", "app", appId);
		} catch (NoticeCommandException e) {
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
			throw e;
		} catch (ApmDataIndicatorException e) {
			ExceptionUtils.error(log, "保存拓扑失败", e);
			throw e;
		}
		return vo_services;
	}

	@Override
	public List<Service> saveTopologyNodesAndCluster(String appId, List<Service> list, String panelId) throws Exception {
		List<Service> services = null;
		if (list != null && list.size() > 0) {
			for (int i = 0; i < list.size(); i++) {
				Service serv = list.get(i);
				if (serv == null)
					continue;
				// 新增单个节点
				if ((serv.getId() != null && !StringUtils.contains(serv.getId(), appId))
						|| (serv.getId() == null && serv.getNodeType() == Common_Type) || (serv.getId() == null && serv.getNodeType() == Label_Type)) {

					String check = LicUtils.check();
					if (check != null) {
						throw new Exception(check);
					 }
					services = saveApplicationTopologyNodes(appId, list);
					break;
				}
				// 新增、修改集群节点
				if (serv.getId() == null || i == (list.size() - 1)) {
					services = saveApplicationTopologyCluster(appId, list);
					break;
				}
			}
		}
		if (services != null) {
			for (Service service : services) {
				// 设置指标配置项
				service.setIndicatorConfig(
						IndicatorItemManager.getInstance().getTopoItems(service.getAutoDiscoveryProtocol() > 0
								? service.getAutoDiscoveryProtocol() : service.getProtocol(), panelId));
			}
		}
		return services;
	}
	
	private List<Service> saveApplicationTopologyNodes(String appId, List<Service> list) throws Exception {
		List<Service> services = new ArrayList<Service>();
		try {
			ApmLogUtils.backupTopology("front", 1, "saveApplicationTopologyNodes", appId);
			com.broada.apm.model.ApplicationSystem app = applicationService.getApplicationWithServiceAndRelById(appId);
			
			Map<String, Service> updatedSet = Maps.newHashMap();
			for (Service service : list) {
				String appServiceId = null;
				List<Service> disServiceList = new ArrayList<Service>();
				// 标签节点
				if (service.getNodeType() == Label_Type) {
					String serviceId = UUID.randomUUID().toString().replace("-","");
					appServiceId = appId + "-" + serviceId;
					int x = list.get(0).getX();
					int y = list.get(0).getY();
					service.setSize("large");
					service.setCreateBy("manual");
					service.setNodeType(Label_Type);
					service.setId(appServiceId);
					service.setCreatedAt(new Date());
					service.setX(x);
					service.setY(y);
					serLogic.saveService(service);
					updatedSet.put(appServiceId, service);
				} else {
					long ipNum = IPUtils.toLong(service.getIp());
					appServiceId = IdUtils.serviceIdWithApp(appId, com.broada.apm.model.Service.TCP, ipNum,
							service.getPort());
					if (app.getServiceIds() != null && ArrayUtils.contains(app.getServiceIds(), appServiceId)) {
						throw new Exception("不能重复添加节点");
					}
					if (StringUtils.isBlank(service.getId())) {
						disServiceList = serLogic.queryDisServiceByIpAndPort(service.getIp(), service.getPort());
					}
					//手工添加
					if (StringUtils.isBlank(service.getId()) && disServiceList.size() <= 0) {
						service.setSize("large");
						service.setCreateBy("manual");
						service.setNodeType(service.getNodeType());
						service.setCreatedAt(new Date());
						service.setIpNum(IPUtils.toLong(service.getIp()));
						service.setId(IdUtils.serviceId(com.broada.apm.model.Service.TCP, IPUtils.toLong(service.getIp()),
								service.getPort()));
						// 手工添加节点协议默认为1
						if (service.getProtocol() == 0) {
							service.setProtocol(1);
						}
//						service.setFocus(1);
						serLogic.saveDisService(service);
						if (service.getProtocol() != 0)
							L7ModuleManager.setL7Module(0, service.getProtocol(), service.getIp(), service.getPort());
					}
					Service disService = null;
					if (disServiceList.size() > 0) {
						disService = disServiceList.get(0);
					} else {
						disService = serLogic.queryDisServiceById(service.getId());
					}
					if (disService == null) {
						throw new Exception("没有找到服务");
					}
					
					int x = list.get(0).getX();
					int y = list.get(0).getY();
					disService.setName(service.getName());
//					disService.setFocus(1);
					// 修改自动发现节点名称
					serLogic.updateDisService(disService);
					// 修改所有系统的对应节点的名称
//				changeServiceName(service.getName(), disService.getIp(), disService.getPort());
					disService.setSize("large");
					disService.setNodeType(Common_Type);
					disService.setId(appServiceId);
					disService.setCreatedAt(new Date());
					disService.setNext(service.getNext());
					disService.setPrevious(service.getPrevious());
					disService.setX(x);
					disService.setY(y);
					serLogic.saveService(disService);
					updatedSet.put(appServiceId, disService);
				}
				
			}
			services.addAll(updatedSet.values());
//			result.addData(Constants.TOPONODES, updatedSet.values());
			
			List<String> relationIds = saveRelation(updatedSet.values());
			if (relationIds.size() == 0){
				relationIds = saveRelationNoDirection(app, updatedSet.values());
			}
			if (app.getRelationIds() != null && app.getRelationIds().length > 0)
				relationIds.addAll(Arrays.asList(app.getRelationIds()));

			app.setRelationIds(relationIds.toArray(new String[relationIds.size()]));
			
			Set<String> oldSeviceIds = Sets.newHashSet(app.getServiceIds() == null ? new String[0] : app.getServiceIds());
			oldSeviceIds.addAll(updatedSet.keySet());
			app.setServiceIds(oldSeviceIds.toArray(new String[oldSeviceIds.size()]));
			
			applicationService.updateApplicationWithRelation(app);
			indicatorService.NoticeCommand("reload", "app", app.getId());
		}  catch (NoticeCommandException e) {
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
			throw e;
		} catch (ApmDataIndicatorException e) {
			ExceptionUtils.error(log, "保存拓扑图失败", e);
			throw e;
		}
		return services;
	}
	
	private List<String> saveRelation(Collection<Service> services) throws Exception {
		List<String> relationIds = Lists.newArrayList();
		Relation rela = null;
		for (Service service : services) {
			if (!Strings.isNullOrEmpty(service.getNext())) {
				String id = UUID.randomUUID().toString();
				relationIds.add(id);
				rela = new Relation();
				rela.setId(id);
				rela.setFrom(service.getId());
				rela.setTo(service.getNext());
				relaLogic.saveRelation(rela);
			} else if (!Strings.isNullOrEmpty(service.getPrevious())) {
				String id = UUID.randomUUID().toString();
				relationIds.add(id);
				rela = new Relation();
				rela.setId(id);
				rela.setFrom(service.getPrevious());
				rela.setTo(service.getId());
				relaLogic.saveRelation(rela);
			}
		}
		return relationIds;
	}
	
	private List<String> saveRelationNoDirection(com.broada.apm.model.ApplicationSystem app, Collection<Service> services) {
		List<String> relationIds = Lists.newArrayList();
		if (app.getServiceIds() == null || app.getServiceIds().length == 0)
			return relationIds;
		try {
			List<com.broada.apm.model.Service> oldServices = serviceService.getServicesByAppId(app.getId());
			for (Service newSer : services) {

				for (com.broada.apm.model.Service oldSer : oldServices) {
					Set<Long> oldIps = Sets.newHashSet();
					Set<String> oldServiceIds = Sets.newHashSet();
					if (oldSer.getNodeType() == Cluster_Type) {
						List<com.broada.apm.model.Service> clusterNodes = serviceService.getChildServiceByClusterId(oldSer.getId());
						for (com.broada.apm.model.Service clusterNode : clusterNodes) {
							oldIps.add(clusterNode.getIpNum());
							oldServiceIds.add(IdUtils.serviceId(com.broada.apm.model.Service.TCP, IPUtils
									.toLong(clusterNode.getIp()), clusterNode.getPort()));
						}
					} else {
						oldIps.add(oldSer.getIpNum());
						oldServiceIds.add(IdUtils.serviceId(com.broada.apm.model.Service.TCP, IPUtils.toLong(oldSer
								.getIp()), oldSer.getPort()));
					}
					// 查找上级关系
					String serviceId = IdUtils.serviceId(com.broada.apm.model.Service.TCP, IPUtils.toLong(newSer
							.getIp()), newSer.getPort());
					List<ProtocolRelation> relations = new ArrayList<ProtocolRelation>();
					List<ProtocolRelation> rels = relationService.getDisRelationByServiceId(serviceId);
					for(ProtocolRelation r : rels) {
						if(oldIps.contains(r.getSrcIp())) {
							relations.add(r);
						}
					}
					
					if (relations != null && relations.size() > 0) {
						String id = UUID.randomUUID().toString();
						com.broada.apm.model.Relation rela = new com.broada.apm.model.Relation();
						rela.setId(id);
						rela.setFrom(oldSer.getId());
						rela.setTo(newSer.getId());
						relationService.addRelation(rela);
						relationIds.add(id);
					}
					
					relations.clear();
					
					// 查找下级关系
					rels = relationService.getDisRelationBySrcIp(newSer.getIpNum());
					for(ProtocolRelation r : rels) {
						if(oldServiceIds.contains(r.getServiceId())) {
							relations.add(r);
						}
					}
					if (relations != null && relations.size() > 0) {
						String id = UUID.randomUUID().toString();
						com.broada.apm.model.Relation rela = new com.broada.apm.model.Relation();
						rela.setId(id);
						rela.setFrom(newSer.getId());
						rela.setTo(oldSer.getId());
						relationService.addRelation(rela);
						relationIds.add(id);
					}
				}
			}

		} catch (Exception e) {
			ExceptionUtils.error(log, "自动连线异常", e);
		}
		return relationIds;
	}

	@Override
	public boolean deleteApplicationTopologyNodesByNodeIds(String appId,
			String nodeId) {
		boolean result = true;
		try {
			ApmLogUtils.backupTopology("front", 1, "deleteApplicationTopologyNodesByNodeIds", appId);
			com.broada.apm.model.ApplicationSystem app = applicationService.getApplicationWithServiceAndRelById(appId);
			String[] nodeIds = app.getServiceIds();
			String[] relaIds = app.getRelationIds();
			// 如果节点为集群
			Service serv = serLogic.queryServiceById(nodeId);
			if (serv != null && serv.getNodeType() == 2 && !ArrayUtils.isEmpty(serv.getNodeIds())) {
				serLogic.deleteServiceByIds(serv.getNodeIds());
				for (String id : serv.getNodeIds()) {
					// 删除子节点告警阀值配置
					alertLogic.deleteThresholdsByTargetId(appId, id, "threshold", null);
					alertLogic.deleteThresholdsByTargetId(appId, id, "algorithm", "system");
					alertLogic.deleteThresholdsByTargetId(appId, id, "algorithm", "business");
					nodeIds = (String[]) ArrayUtils.removeElement(nodeIds, id);
				}
			}
			// 删除选中节点
			serLogic.deleteServiceById(nodeId);
			// 删除选中节点阀值配置
			alertLogic.deleteThresholdsByTargetId(appId, nodeId, "threshold", null);
			alertLogic.deleteThresholdsByTargetId(appId, nodeId, "algorithm", "system");
			alertLogic.deleteThresholdsByTargetId(appId, nodeId, "algorithm", "business");
			nodeIds = (String[]) ArrayUtils.removeElement(nodeIds, nodeId);
			// 删除对应关系
			List<Relation> relas = relaLogic.queryRelationByFromOrTo(new String[]{nodeId});
			for (Relation rela : relas) {
				relaIds = (String[]) ArrayUtils.removeElement(relaIds, rela.getId());
			}
			relaLogic.deleteRelationByFromOrTo(new String[]{nodeId});
			app.setServiceIds(nodeIds);
			app.setRelationIds(relaIds);
			applicationService.updateApplicationWithRelation(app);
			indicatorService.NoticeCommand("reload", "apps");
		} catch (NoticeCommandException e) {
			ExceptionUtils.error(log, "通知Indicator模块异常", e);
		} catch (Exception e) {
			ExceptionUtils.error(log, "删除拓扑节点失败", e);
			result = false;
		}
		return result;
	}

	@Override
	public List<Relation> queryApplicationTopologyRelations(String appId,
			String[] nodeIds) {
		List<Relation> relas = new ArrayList<Relation>();
		try {
			com.broada.apm.model.ApplicationSystem app = applicationService.getApplicationWithServiceAndRelById(appId);
			if (app != null && app.getServiceIds() != null) {
				String[] oldNodeIds = app.getServiceIds();
				Set<String> tSet = Sets.newHashSet();
				if (oldNodeIds != null && oldNodeIds.length != 0)
					tSet.addAll(Arrays.asList(oldNodeIds));
				if (nodeIds != null && nodeIds.length != 0)
					tSet.addAll(Arrays.asList(nodeIds));
				for (String id : nodeIds) {
					Set<String> nSet = Sets.newHashSet(tSet);
					nSet.remove(id);
					if (nSet.isEmpty())
						continue;
					List<Relation> list = relaLogic.queryRelationByFromAndTo(nSet.toArray(new String[nSet.size()]), new String[]{id});
					relas.addAll(list);

					// 查找向下关系
					list = relaLogic.queryRelationByFromAndTo(new String[]{id}, nSet.toArray(new String[nSet.size()]));
					relas.addAll(list);
				}
			}
		} catch (Exception e) {
			ExceptionUtils.error(log, "查询关系失败", e);
		}
		return relas;
	}

	@Override
	public boolean changeApplicationOrder(String appid1, String appid2) {
		try {
			com.broada.apm.model.ApplicationSystem app1 = applicationService.getApplicationById(appid1);
			com.broada.apm.model.ApplicationSystem app2 = applicationService.getApplicationById(appid2);
			long app1pos = app1.getDisplayOrder();
			app1.setDisplayOrder(app2.getDisplayOrder());
			app2.setDisplayOrder(app1pos);
			applicationService.updateApplication(app1);
			applicationService.updateApplication(app2);
			return true;
		} catch (Exception e) {
			ExceptionUtils.error(log, "排序失败", e);
		}
		return false;
	}

	@Override
	public List<AO> queryAOSByAppId(String appId, String panelId) {
		List<AO> aos = new ArrayList<AO>();
		List<String> targetIds = Lists.newArrayList();
		List<Threshold> thresholds = alertLogic.queryThresholdsByApplicationId(appId, panelId);
		if (!thresholds.isEmpty()) {
			for (Threshold threshold : thresholds) {
				targetIds.add(threshold.getTargetId());// 已配置阈值的节点或资源id
			}
		}
		try {
			List<com.broada.apm.model.Service> services = serviceService.getServicesByAppId(appId);
			for(com.broada.apm.model.Service service : services) {
				if(service.getNodeType() != 2 && service.getNodeType() != 4 && !targetIds.contains(service.getId())) {//非集群节点且未配置阈值的节点
					AO ao = new AO();
					ao.setId(service.getId());
					ao.setName(service.getName());
					aos.add(ao);
				}
			}
			
			List<Resource> resources = resourceService.getKeyResourcesByAppId(appId);
			for(Resource resource : resources) {
				if(!targetIds.contains(resource.getId())) {
					com.broada.apm.model.Service ser = serviceService.getServiceById(IdUtils.serviceIdWithApp(resource.getApplicationId(), resource.getBelongTo()));
					if (ser != null && ser.getNodeType() == 2) continue; // 集群节点的关键交易不能配置阈值
					AO ao = new AO();
					ao.setId(resource.getId());
					if(ser != null) {
						ao.setName(resource.getUri() + "@" + ser.getName());
					} else {
						ao.setName(resource.getUri());
					}
					aos.add(ao);
				}
			}
		} catch (Exception e) {
			ExceptionUtils.error(log, e.getMessage(), e);
		}
		return aos;
	}

	@Override
	public List<String> queryApplicaitonProtocals(ApplicationSystem application) {
		List<String> protocalList = new ArrayList<String>();
		List<Service> nodeList = new ArrayList<Service>();
		try {
			nodeList = serLogic.queryServiceByAppId(application.getId());
			// 查询节点协议类型
			for (Service serv : nodeList) {
				String protocalId = serv.getProtocol() == 0 ? serv.getAutoDiscoveryProtocol() + "" : serv.getProtocol() + "";
				com.broada.apm.model.L7Module module = l7ModuleService.getL7ModuleById(protocalId);
				if (!protocalList.contains(module.getCname())) {
					protocalList.add(module.getCname());
				}
			}

		} catch (Exception e) {
			ExceptionUtils.error(log, "查询系统协议失败", e);
		}
		return protocalList;
	}

	@Override
	public List<String> queryApplicaitonIps(ApplicationSystem application) {
		List<String> ips = new ArrayList<String>();
		List<Service> nodeList = new ArrayList<Service>();
		try {
			nodeList = serLogic.queryServiceByAppId(application.getId());
			// 查询节点协议类型
			for (Service serv : nodeList) {
				if (serv.getNodeType() == 2) {
					continue;
				}
				ips.add(serv.getIp());
			}
		} catch (Exception e) {
			ExceptionUtils.error(log, "查询当前系统所有节点IP失败", e);
		}
		
		return ips;
	}

	@Override
	public com.broada.apm.model.ApplicationSystem getApplicationByName(String appName) {
		return applicationService.getApplicationByAppName(appName);
		
	}

	@Override
	public List<ApplicationSystem> getApplicationByCondition(boolean inOverview, String keyWord) {
		List<ApplicationSystem> apps = new ArrayList<ApplicationSystem>();
		try {
			com.broada.apm.model.ApplicationSystem application = new com.broada.apm.model.ApplicationSystem();
			application.setOverview(inOverview);
			if (StringUtils.isNotBlank(keyWord)) {
				application.setName(keyWord);
			}
			List<com.broada.apm.model.ApplicationSystem> appList = applicationService.getApplicationByCondition(application);
			apps = BeanConvert.convertApplication(appList);
		} catch (Exception e) {
			ExceptionUtils.error(log, "查询交易总览页面应用系统失败", e);
			throw e;
		}
		return apps;
	}

	@Override
	public void updateAppOverviewStatus(ApplicationSystem application) {
		com.broada.apm.model.ApplicationSystem app = applicationService.getApplicationById(application.getId());
		app.setOverview(application.getIsOverview());
		if (application.getIsOverview() == true) {
			app.setBusinessDisplayOrder(System.currentTimeMillis());
		}
		applicationService.updateApplication(app);
	}

	@Override
	public void saveAppsInOverview(List<String> appIds) {
		applicationService.saveAppsInOverview(appIds);
		
	}

	@Override
	public boolean changeBusinessApplicationOrder(String appid1, String appid2) {
		try {
			com.broada.apm.model.ApplicationSystem app1 = applicationService.getApplicationById(appid1);
			com.broada.apm.model.ApplicationSystem app2 = applicationService.getApplicationById(appid2);
			long app1pos = app1.getBusinessDisplayOrder();
			app1.setBusinessDisplayOrder(app2.getBusinessDisplayOrder());
			app2.setBusinessDisplayOrder(app1pos);
			applicationService.updateApplication(app1);
			applicationService.updateApplication(app2);
			return true;
		} catch (Exception e) {
			ExceptionUtils.error(log, "排序失败", e);
		}
		return false;
	}

	@Override
	public List<ApplicationSystem> queryApplicationsByIds(String[] appIds) {
		List<ApplicationSystem> apps = new ArrayList<ApplicationSystem>();
		List<com.broada.apm.model.ApplicationSystem> appList = applicationService.queryApplicationsByIds(appIds);
		apps = BeanConvert.convertApplication(appList);
		return apps;
	}

	@Override
	public com.broada.apm.model.ApplicationSystem getApplicationById(String appId) {
		return applicationService.getApplicationById(appId);
	}

	@Override
	public List<String> queryApplicationIdsBySystem(String appId) {
		// TODO Auto-generated method stub
		return null;
	}
}
